/*
 * 
 */
package com.bonshotels.DomainLayer.DomainModel;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * La PreuTipusHabitacio actua en el nostre disseny amb el rol del client d'un patró estrategia.
 * Per aixo te un pseudoatribut IEstrategiaCalculPreu que es la interficie que acompliran les
 * diferents estrategies concretes de calcul del preu.
 * Com que utilitzem el framework de persistencia
 * Hibernate i aquest utilitza reflexio per fer la seva feina les nostres classes han d'acomplir una
 * serie de propietats perque la reflexio del Hibernate pugui fer completament la seva feina, les
 * classes han de ser publiques, han de tenir un constructor public buit (si no en tenen un d'explicit
 * el per defecte ja ho es), han d'implementar Serializable, i han de tenir substituits (override) els
 * metodes equals() i hashCode() perque identifiquin les classes a partir de la seva clau natural.
 * Com que PreuTpusHabitacio s'identifica pel seu hotel i el seu tipus d'habitacio, malgrat que en
 * la fase de disseny no vam definir navegabilitat de PreuTipusHabitacio a Hotel a l'hora
 * d'implementar equals(), hashCode() i els mapping de Hibernate ens ha fet falta i l'hem hagut
 * d'afegir.
 * @author Marc Mauri Alloza
 */
public class PreuTipusHabitacio implements Serializable {

	/** La constant serialVersionUID. */
	private static final long serialVersionUID = 7282888585801965314L;

	/** El preu base per nit d'estada. */
	private float preu;
	
	/** L'estrategia de calcul del preu total. */
	private IEstrategiaCalculPreu iECP;
	
	/** El tipus de l'habitacio que te aquest preu. */
	private TipusHabitacio tH;
	
	/** The hotel. */
	private Hotel hotel;
	
	/**
	 * Getter de serialversionuid.
	 *
	 * @return El serialversionuid
	 */
	public static long getSerialversionuid() {
		return serialVersionUID;
	}
	
	/**
	 * Calcula el preu final utilitzant la estrategia de calcul del preu a partir del preu base.
	 *
	 * @return El preu final.
	 */
	float calculaPreu() {
		return iECP.calcularPreu(preu);
	}
	
	/**
	 * Obte les dades del tipus d'habitacio associat al preu.
	 *
	 * @param numOcup El numero d'ocupants que volen ocupar una habitacio.
	 * @return Un Map amb el nom del tipus d'habitavio (key: "nomTipus"), si numOcup i caben o no
	 * (key: "hiCaben") i amb el preu final (key: "preuTipus")
	 */
	Map<String, Object> obteDadesTipusHabitacio(int numOcup) {
		Map<String, Object> dadesTipus = tH.hiCaben(numOcup);
		boolean hiCaben = ( (Boolean)dadesTipus.get("hiCaben") ).booleanValue();
		String nomTipus = (String)dadesTipus.get("nomTipus");
		if (hiCaben) {
			float preuFinal = calculaPreu();
			dadesTipus.put("preuTipus", preuFinal);
			dadesTipus.put("nomTipus", nomTipus);
		}
		return dadesTipus;
	}
	
	/**
	 * Calcula el preu que comportaria reservar lhabitacio els dies compresos entre 'dataInici'
	 * i 'dataFi' i diu si el preu es correspon a un tipus d'habitacio amb nom tipusHab.
	 *
	 * @param tipusHab El nom del tipus d'habitacio al que volem saber si es correspon el preu.
	 * @param dataInici La data d'inici de la reserva.
	 * @param dataFi la data de fi de la reserva.
	 * @return Un Map amb el preu final (key: "preuFinal") i si el preu es correspon a un tipus
	 * d'habitacio amb nom tipusHab (key: "trobat")
	 */
	Map<String, Object> calculaPreuTipus(String tipusHab, Date dataInici, Date dataFi) {
		Map<String, Object> dadesPreu = new TreeMap<String, Object>();
		boolean trobat = tH.esTipus(tipusHab);
		dadesPreu.put("trobat", trobat);
		//el preu per dia aplicant ofertes per la diferencia de milisegons entre dates passada a dies
		float preuFinal = (calculaPreu()*( (dataFi.getTime() - dataInici.getTime() )/(1000*60*60*24)))-1;		
		dadesPreu.put("preuFinal", preuFinal);
		return dadesPreu;
	}

	/**
	 * Getter del preu.
	 *
	 * @return El preu.
	 */
	public float getPreu() {
		return preu;
	}

	/**
	 * Setter del preu.
	 *
	 * @param preu El nou preu
	 */
	public void setPreu(float preu) {
		this.preu = preu;
	}

	/**
	 * Getter d'iECP.
	 *
	 * @return El iECP
	 */
	public IEstrategiaCalculPreu getiECP() {
		return iECP;
	}

	/**
	 * Setter d'iECP.
	 *
	 * @param iECP El nou iECP
	 */
	public void setiECP(IEstrategiaCalculPreu iECP) {
		this.iECP = iECP;
	}

	/**
	 * Getter de tH.
	 *
	 * @return El tH
	 */
	public TipusHabitacio gettH() {
		return tH;
	}

	/**
	 * Setter de tH.
	 *
	 * @param tH El nou tH
	 */
	public void settH(TipusHabitacio tH) {
		this.tH = tH;
	}
	
	/**
	 * Getter d'hotel.
	 *
	 * @return L'hotel
	 */
	public Hotel getHotel() {
		return hotel;
	}

	/**
	 * Setter d'hotel.
	 *
	 * @param hotel El nou hotel
	 */
	public void setHotel(Hotel hotel) {
		this.hotel = hotel;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((hotel == null) ? 0 : hotel.hashCode());
		result = prime * result + ((tH == null) ? 0 : tH.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PreuTipusHabitacio other = (PreuTipusHabitacio) obj;
		if (hotel == null) {
			if (other.hotel != null)
				return false;
		} else if (!hotel.equals(other.hotel))
			return false;
		if (tH == null) {
			if (other.tH != null)
				return false;
		} else if (!tH.equals(other.tH))
			return false;
		return true;
	}

}
